perm filename NCOMPL.RPG[UP,DOC]2  blob 
sn#325226 filedate 1977-12-21 generic text, type C, neo UTF8
 
COMMENT ⊗   VALID 00013 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002		The MACLISP compiler is called NCOMPLR  (for Number COMPiLeR)
C00007 00003				 A User's Guide to the
C00010 00004
C00013 00005
C00016 00006
C00019 00007
C00022 00008
C00025 00009
C00028 00010
C00031 00011
C00034 00012
C00037 00013
C00038 ENDMK
C⊗;
	The MACLISP compiler is called NCOMPLR  (for Number COMPiLeR)
and  is noted for  being the  "best" LISP  compiler in  existence. In
particular there are facilities for declaring the types of objects so
that a  fair amount of  open-coding is  possible; this is  especially
nice for numerical  computations (hence the "N" in NCOMPLR). For more
information on this either locate an old MACLISP manual or ask RPG or
WLS.
	To compile a file do:
		R NCOMPLR
		<target>←FN.EXT<(SWITCHES)>
The <target>  is optional  and defaults  accordding to the  switches.
Briefly the switches are:
	T 	Talk: verbose mode
	A	Assemble: take a .LAP file and assemble it
	F	Fasload: take a source file and compile & assemble it
	K  	Kill: take a source file and compile & assemble it but 
		kill the LAP file
The default names  are FN.LAP for a  compiled file and FN.FAS  for an
assembled file.  NCOMPLR understands ALIASes.
	One can inform the compiler about one's intentions by placing
DECLARATIONs in the file. DECLARATIONs are of the form:
		(DECLARE <decl1><decl1>...<decln>)
The compiler actually evauates each of the <decli>'s so
that (DECLARE (EVAL (READ))) is meaningful.
Some important other declarations are:
(SPECIAL var1 var2 ...) Says that var1, var2, etc are special
(UNSPECIAL var1 var2 ...) Says that var1, var2, etc are local
(*EXPR fn1 fn2 ..) fn1, fn2 etc are EXPRs
(*LEXPR fn1 ...) fn1 etc are LEXPRs
(*FEXPR fn1 ...) fn1 etc are FEXPRs
(**ARRAY arr1 ...) arr1 etc are arrays
(FIXNUM v1 ...) v1 etc are fixnums
(FLONUM v1 ...) v1 etc are flonums
(FIXNUM (fn1 type1 ...) ...) fn1 etc returns a fixnum and its arguments are
			     of the type specified.
(FLONUM (fn1 type1 ...) ...) as above
(NOTYPE v1 (fn1 type1 ...) ...) v1, fn1, etc have no type
(FIXSW T) all arithmetic is FIXNUM except that denoted by +$ etc
(FLOSW T) all arithmetic is FLONUM except that denoted by + etc
(FIXSW NIL)(FLOSW NIL) shuts off above
(SETQ SPECIAL T) all variables are special
(SETQ NFUNVARS T) no functional values allowed
(MACROS T) causes macros to be defined at runtime as well as compile time
(MACROS NIL) shuts off above
(GENPREFIX foo) causes auxilliary functions generated by the compiler to be
		named foon etc.
(ARRAY* (type arr1 n1 arr2 n2 ...)...) says that arr1, arr2 etc are of type type
				       and  that arr1 is n1 dimensional etc.
(ARITH (type1 fn1 ...) ...) says to replace a general arithmetic function with
			    a one-type function. Thus (ARITH (FIXNUM PLUS))
			    will replace occurrences of PLUS with +.
(MAPEX T) open code MAP type functions
(NOARGS T) suppress number-of-args information (saves space)
(MESSIOC chars) does (IOC chars), used for suppressing error messages or
	        directing them to the LAP file
(MUZZLED T) suppresses closed-compilation messages
			 A User's Guide to the
	      Fast Arithmetic Feature of the Lisp Compiler
							  Eric Rosen
							     4/25/72
    1- Introduction
	    The fast-arithmetic feature of NCOMPLR attempts to  take
    advantage  of the new uniform representation of numbers in NLISP
    by   open-coding  arithmetic  expressions,  i.e.  by  generating
    machine instructions  to do  arithmetic, in  lieu of  generating
    calls  to LISP's  arithmetic functions.   It  will also generate
    compare or conditional  jump instructions  in lieu  of calls  to
    MINUSP,  ZEROP, PLUSP,  GREATERP, LESSP, SIGNP,  and for numeric
    arguments, EQUAL.   In order to  facilitate this, the user  MUST
    make  declarations to the compiler,  so the compiler knows which
    of the user's functions and variables have numerical values, and
    whether  these  values  are  fixnum  or  flonum.   The  compiler
    introduces  a  new  data  type  which  has  no  analogue  in the
    interpreter, i.e.  number  quantities.   A  number  quantity  is
    merely a machine number.  A LISP number is actually a pointer to
    a  word  in  garbage-collectable FIXNUM  or  FLONUM  space which
    contains a  machine  number;  a  number quantity  is  a  machine
    number  itself, with no intervening pointer.   The compiler will
    automatically handle  the  intermediate  results  of  open-coded
							      PAGE 2
    arithmetic expressions as number quantities.   Also, by suitable
    use of  declarations,  the user  may  inform the  compiler  that
    certain of his variables are to be treated as number quantities.
    Number  quantities are not  stored in garbage-collectable space,
    but on the FIXNUM or FLONUM PDLs.
	    Open compilation is, of course, only relevant to single-
    word arithmetic.   Those users who  wish to utilitize  infinite-
    precision  integer arithmetic (BIGNUMS) MUST close-compile their
    code.
    2- Number Variables 
	    The following declarations enable  the user to tell  the
    ccmpiler  which of his variables are always going to have either
    fixnum or flonum values, and  whether these values are fixed  or
    floating point:
	    (DECLARE (FIXNUM XVAR1 XVAR2 ...  XVARn)
		     (FLONUM LVAR1 LVAR2 ...  LVARn))
    In  the case of  local variables (i.e.  variables which have not
    been declared or made special) these declarations indicate  that
    the value of the variable is a number quantity.   In the case of
    special variables, these declarations  indicate to the  compiler
    that  the value of  the variable is  a LISP number  of the given
    type.   (For technical reasons, no  special variable can have a
    number quantity as its value.)
	    It  is important to realize  that number variables, i.e.
							      PAGE 3
    variables whose values  are number quantities,  do not exist  in
    the interpreter.   Thus a number variable is not a LISP variable
    in the usual sense, and  there are restrictions on its  use.   A
    NUMBER  VARIABLE MAY NEVER  HAVE ANY OTHER  VALUE THAN A NUMBER.
    Furthermore, a fixnum  number variable may  never have a  flonum
    value,  and  vice  versa.   If these  restrictions  are ignored,
    errors will  result.   The  compiler  will try  to  detect  such
    errors,  but most  of them cannot  be detected  at compile time.
    Thus the  user  must  be  very careful  to  pay  heed  to  these
    restrictions.   FAILURE  TO DO SO WILL  MEAN THAT CODE WHICH MAY
    RUN PERFECTLY WELL  UNDER THE INTERPRETER  WILL RUN  ERRONEOUSLY
    WHEN  COMPILED.   The user  should be  particularly careful with
    PROG variables that are also number variables.   The interpreter
    initializes  all PROG variables  to NIL.   However, since number
    variables may not have the  value NIL, the compiler  initializes
    number  PROG  variables   to  0  or   0.0.    Because  of   this
    inconsistency  with  the  interpreter,  IT IS  AN  ERROR  TO USE
    NUMERIC PROG  VARIABLES BEFORE  INITIALIZING THEM.   Again,  the
    compiler will try to detect these errors, but will not always be
    able to.
	    It  is, of  course, permissible  to SETQ  or LAMBDA-bind
    number variables to any expression  whose value is a number,  be
    it  a number quantity or a LISP number.   It is also permissible
    to SETQ or LAMBDA-bind LISP variables to number  variables.   In
    all  cases the compiler will cause  the correct conversion to be
							      PAGE 4
    done.
	    It should be realized that if a number quantity is  ever
    CONS'd into a list structure, it will have to first be converted
    into  a  LISP number.   This  is  relatively expensive  in time,
    because repeated number CONSing will cause more frequent garbage
    collections.   The compiler makes every  effort to avoid  number
    CONSing,  and  therefore  number  CONSing  is  done  only   when
    absolutely  necessary.   However if the user keeps any numerical
    parameters for the purpose of CONSing them into lists, he may be
    better off  making  them regular  LISP  variables.   (Parameters
    which  are to be used in  arithmetic computation are, of course,
    best kept in number variables.)
	    The following declaration is available for negating  the
    effect of previous FIXNUM or FLONUM declarations.
	    (DECLARE (NOTYPE VAR1 VAR2 ...  VARn))
    3- Declaring functions
	    The  following declarations are  available for declaring
    functions to the compiler:  
	    (DECLARE (FIXNUM (XFN1 ARG1 ...   ARGn) ...   (XFNm ARG1
    ...  ARGn)) 
		     (FLONUM (LFN1 ARG1 .. .  ARGn) .. .  (LFNm ARG1
    ...  ARGn)) 
		     (NOTYPE (NFN1 ARG1 ...   ARGn) ...   (NFNm ARG1
    ...  ARGn)))
							      PAGE 5
    Of  course,  variable  declarations  may  be  intermingled  with
    function declarations as in:
	    (DECLARE (FIXNUM VAR1 VAR2 (FN FIXNUM NOTYPE)))
    The arguments to these  FIXNUM, FLONUM, and NOTYPE  declarations
    are  lists.   The CAR of  each list is the  name of the function
    being declared.   The CDR of each list is a list of the types of
    the  arguments  of the  functions, where  each argument  type is
    either 'FIXNUM'  (or, as  an abbreviation,  any fixnum  number),
    'FLONUM'  (or any flonum number),  or 'NOTYPE' (or 'NIL').   The
    main declaration tells what kind of value the function  returns.
    Hence  these declarations have the effect of both declaring what
    kinds of arguments the function takes, and what kind of value it
    returns.
	    For example,  suppose function  FOO returns  a  floating
    point  number.   Further, suppose  FOO has  three arguments  - a
    fixed-point number, a random list, and a floating point  number.
    The appropriate declaration is:
	    (DECLARE (FLONUM (FOO FIXNUM NOTYPE FLONUM)))
    Suppose  BAR  is just  like FOO,  except that  its value  is not
    numeric.  The appropriate declaration is:
	    (DECLARE (NOTYPE (BAR FIXNUM NOTYPE FLONUM)))
    Arguments may be omitted on the  right, in which case NOTYPE  is
    assumed.	 For instance, if  FOOBAR has three  arguments , the
    following two declarations are completely equivalent:
							      PAGE 6
	    (DECLARE (FIXNUM (FOOBAR FLONUM NOTYPE NOTYPE)))
    and 
	    (DECLARE (FIXNUM (FOOBAR FLONUM)))
    THE SAME  DECLARATION  MUST  BE  IN FORCE  WHEN  A  FUNCTION  IS
    COMPILED  AS WHEN A CALL TO THAT FUNCTION IS COMPILED.   If this
    rule is not followed, the functions may not interface  properly,
    causing  random results and/or  LISP errors.   Compiled functons
    should interface properly with  uncompiled functions ,  however,
    regardless of declaratons.  
    4- Scope of declarations
	    Declarations are either global, or local to the nearest-
    enclosing PROG or LAMBDA in which they appear.  If a declaration
    occurs  which is not within a function definition, it is global.
    It maintains  its  effects  until countermanded  by  some  other
    global  declaration  or  temporarily   overridden  by  a   local
    declaration.   Local  declarations should  always appear  as the
    first statements  of the  PROG or  LAMBDA in  which they  occur.
    They  affect only  the PROG or  LAMBDA in which  they occur, and
    they take precedence over any conflicting global or superior (in
    position) local declarations.
	    When a  function  declaration  is used  to  declare  the
    arguments  of the  function, the scope  is just  the function in
    question.   
	    Only FIXNUM, FLONUM, and  NOTYPE declarations are  legal
							      PAGE 7
    as  local declarations.   All other declarations must be global,
    i.e. they cannot appear within a function body.  It is not legal
    to locally  undeclare  a  variable (i.e.  by  using  the  NOTYPE
    declaration).  The only use of local function declarations is to
    declare  bound variable functions.   For example, where 'X' is a
    bound variable the declaration
	    (DECLARE (FIXNUM (X FIXNUM)))
    means that 'X' is bound to a function whose first (perhaps only)
    argument is a fixnum and which returns a fixnum value.  In order
    for this  declaration to  work properly,  all the  functions  to
    which 'X' may be bound must have been so declared when they were
    compiled.
    5- Open-coding arithmetic expressions
	    The  compiler  is  able   to  open-code  the   following
    arithmetic  functions:  PLUS, TIMES, DIFFERENCE, *DIF, QUOTIENT,
    *QUO, ADD1,  SUB1, REMAINDER,  MINUS, ABS,  FIX, FLOAT,  MINUSP,
    PLUSP,  SIGNP,  BOOLE, ROT,  LSH,  GREATERP, LESSP,  and  if its
    arguments are numeric, EQUAL.
	    (DECLARE (CLOSED  T))  inhibits  open-coding.   (DECLARE
    (CLOSED  NIL)) enables it,  and is the  default option.   If the
    compiler cannot figure  out whether the  arguments to the  above
    functions  are fixnums or flonums, it will be forced to generate
    a call  to the  appropriate  routine in  the  interpreter.   The
    compiler  makes use of the  user's declarations to determine the
							      PAGE 8
    types  of  the  arguments.   When  the  compiler  encounters  an
    expression  with an argument whose type it can not determine, it
    tries to open-compile as much of the expression as it  can.   If
    an  expression  has  to be  even  partially  closed-compiled the
    compiler will print a warning message.  This message is expected
    to be of  aid to  users who  would like  open-compiling but  who
    aren't  getting it  because they  forgot to  make a declaration.
    However, users who want  some expressions to be  closed-compiled
    may  want to  inhibit this  message by  saying (DECLARE (MUZZLED
    T)).
	    The compiler also  offers the user  other ways to  force
    open-compilation.     If the user says (DECLARE (FIXSW T)) , the
    compiler   will  assume  that   all  arguments  to  open-codable
    functions (except, of  course, EQUAL) are  fixnums.   Similarly,
    the  user can (DECLARE  (FLOSW T)) if he  is only using flonums.
    The LISP functions + , - , * , /  , | , 1+ , 1- , are just  like
    PLUS  , DIFFERENCE,  TIMES, QUOTIENT, REMAINDER,  ADD1, and SUB1
    except   that  the  former  may   take  only  fixnum  arguments.
    Therefore the compiler is able  to always open-code the  former.
    Similarly,  the  LISP functions  +$, -$,  *$,  /$, 1+$,  and 1-$
    (these are real  dollar signs, not  alt.   modes) may take  only
    flonum arguments, and are always open-coded.   The predicates >,
    <,  and  =  are  also  always  open-coded;  they  correspond  to
    GREATERP,  LESSP,  and EQUAL  except that  they always  have two
    numerical arguments of the same type.   (In these last 3  cases,
							     PAGE 9
    the  compiler need not know which type the arguments are).   The
    third way  to  force  open-coding  is  by  means  of  the  ARITH
    declaration.  The declaration (DECLARE (ARITH (FIXNUM ADD1 SUB1)
    (FLONUM QUOTIENT))) effectively causes all SUB1's to be replaced
    by 1-'s, ADD1's by 1+'s, and QUOTIENTS by /$'s.   To revert back
    to normal (DECLARE (ARITH (NOTYPE ADD1 SUB1 QUOTIENT))).
	    These techniques just described are NOT a substitute for
    declaring variables and  functions.   They are  useful in  cases
    where  the compiler will not be able to determine the type of an
    argument, for instance (PLUS (CAR X) (CADR X)).  Obviously
     the compiler has no way of knowing that (CAR X) is going to  be
    a fixnum.  So in a case like this, there is a definite advantage
    to using + instead of PLUS.  And if all the user's arithmetic is
    in  the same mode, a FIXSW or  FLOSW declaration may be good for
    him.  If a (FIXSW T) declaration is made, the only way to do any
    flonum arithmetic at all is to use a function which assumes that
    its arguments are flonums, e.g. +$. 
    6- Arrays
	    The  user  should  always  declare  his  arrays  to  the
    compiler.  The ARRAY* declaration is available for this purpose.
    (Note  that  'ARRAY*'  is  not '*ARRAY;  the  latter  is  a LISP
    function).  For instance,
	    (DECLARE (ARRAY* (FIXNUM FOO 1 BAR 2)
			     (FLONUM ARY 3)
							     PAGE 10
			     (NOTYPE FOOBAR 1 ARY2 2))) 
    This declares FOO to be a 1-dimensionsal array of fixnums, BAR a
    2-dimensional array  of fixnums,  ARY a  3-dimensional array  of
    flonums,  FOOBAR a 1-dimensional  array of random S-expressions,
    and ARY2  a 2-dimensional  array of  S-expressions.   Undeclared
    arrays  will  be  handled  properly,   but  at  great  loss   of
    efficiency.     It  should  be  understood  that  arrays  cannot
    [currently] contain machine numbers  - only LISP  s-expressions,
    including  LISP numbers, are permitted.   However, by the end of
    calendar year  1973,  there will  be  two new  types  of  arrays
    implemented  in  LISP, the  FIXNUM array  and the  FLONUM array,
    which will in fact contain  machine numbers of the stated  type.
    Accessing  the  elements of  such arrays  will be  open-coded by
    NCOMPLR, and the resultant code should be speed-competitive with
    FORTRAN array  accessing [except  that there  are no  plans  for
    implementing  the  hairier  optimizations  done  by  really good
    FORTRAN compilers}. 
    7- Miscellany
	    The fast-arithmetic compiler  is loaded by  'NCOMPLR}K',
    but  all other interactions with it are exactly the same as with
    complr [command line parsing, compilations switches, etc.]. 
      The code it produces  runs only in  LISPs with version  number
    greater than 400.
	    For general information on LISP, see Lisp Archiv.
							     PAGE 11
	    Any bugs in the NCOMPLR should be reported to Eric Rosen
    (ECR) or Jonl White (JONL).